const timeColors = ['#33B5E5', '#0099CC', '#AA66CC', '#9933CC', '#99CC00', '#669900', '#FFBB33', '#FF8800', '#FF4444', '#CC0000']
const timeDigits = [
  [
    [0, 0, 1, 1, 1, 0, 0],
    [0, 1, 1, 0, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 0, 1, 1, 0],
    [0, 0, 1, 1, 1, 0, 0]
  ], // 0
  [
    [0, 0, 0, 1, 1, 0, 0],
    [0, 1, 1, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [1, 1, 1, 1, 1, 1, 1]
  ], // 1
  [
    [0, 1, 1, 1, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 1, 1, 0, 0, 0],
    [0, 1, 1, 0, 0, 0, 0],
    [1, 1, 0, 0, 0, 0, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 1, 1, 1, 1, 1]
  ], // 2
  [
    [1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 1, 1, 1, 0, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 1, 1, 0]
  ], // 3
  [
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 1, 0],
    [0, 0, 1, 1, 1, 1, 0],
    [0, 1, 1, 0, 1, 1, 0],
    [1, 1, 0, 0, 1, 1, 0],
    [1, 1, 1, 1, 1, 1, 1],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 1, 1]
  ], // 4
  [
    [1, 1, 1, 1, 1, 1, 1],
    [1, 1, 0, 0, 0, 0, 0],
    [1, 1, 0, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 1, 0],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 1, 1, 0]
  ], // 5
  [
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 1, 1, 0, 0, 0],
    [0, 1, 1, 0, 0, 0, 0],
    [1, 1, 0, 0, 0, 0, 0],
    [1, 1, 0, 1, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 1, 1, 0]
  ], // 6
  [
    [1, 1, 1, 1, 1, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 0, 1, 1, 0, 0, 0],
    [0, 0, 1, 1, 0, 0, 0],
    [0, 0, 1, 1, 0, 0, 0],
    [0, 0, 1, 1, 0, 0, 0]
  ], // 7
  [
    [0, 1, 1, 1, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 1, 1, 0]
  ], // 8
  [
    [0, 1, 1, 1, 1, 1, 0],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [1, 1, 0, 0, 0, 1, 1],
    [0, 1, 1, 1, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 0, 1, 1],
    [0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 1, 1, 0, 0],
    [0, 1, 1, 0, 0, 0, 0]
  ], // 9
  [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
  ]// :
]

interface ITimeCanvasNum {
  num: number;
  offsetX: number;
  offsetY: number;
}

interface ITimeCanvasBall {
  offsetX: number;
  offsetY: number;
  color: string;
  g: number;
  vx: number;
  vy: number;
}

export class TimeCanvas {
  context: CanvasRenderingContext2D
  width: number
  height: number
  options: {
    RADIUS: number; // 球半径
    NUMBER_GAP: number; // 数字之间的间隙
    u: number; // 碰撞能量损耗系数
    timeColor: string; // 时间颜色
    colors: string[]; // 彩色小球的颜色
    digit: any[]; // 数字显示
    offsetX: number; // 初始x偏移
    offsetY: number; // 初始y偏移
  }
  currentNums: ITimeCanvasNum[] = [] // 屏幕显示的8个字符
  balls: ITimeCanvasBall[] = [] // 存储彩色的小球

  constructor(context: CanvasRenderingContext2D, width: number, height: number) {
    this.context = context
    this.width = width
    this.height = height
    this.options = {
      RADIUS: 1.2, // 球半径
      NUMBER_GAP: 10, // 数字之间的间隙
      u: 0.4, // 碰撞能量损耗系数
      timeColor: '#1677FF',
      colors: timeColors, // 彩色小球的颜色
      digit: timeDigits, // 数字显示
      offsetX: 0,
      offsetY: 10
    }
  }

  /**
   * 绘制时间
   */
  drawDatetime(): void {
    // 计算需要显示的时间数字信息
    const timeNums = [] as ITimeCanvasNum[]

    const date = new Date()
    const hours = date.getHours()
    const hour1 = Math.floor(hours / 10)
    const hour2 = hours % 10
    timeNums.push({ num: hour1, offsetX: 0, offsetY: 0 })
    timeNums.push({ num: hour2, offsetX: 0, offsetY: 0 })
    // 添加冒号 下同
    timeNums.push({ num: 10, offsetX: 0, offsetY: 0 })

    const minutes = date.getMinutes()
    const minute1 = Math.floor(minutes / 10)
    const minute2 = minutes % 10
    timeNums.push({ num: minute1, offsetX: 0, offsetY: 0 })
    timeNums.push({ num: minute2, offsetX: 0, offsetY: 0 })
    timeNums.push({ num: 10, offsetX: 0, offsetY: 0 })

    const seconds = date.getSeconds()
    const second1 = Math.floor(seconds / 10)
    const second2 = seconds % 10
    timeNums.push({ num: second1, offsetX: 0, offsetY: 0 })
    timeNums.push({ num: second2, offsetX: 0, offsetY: 0 })

    // canvas绘制时的初始x偏移
    let { offsetX } = this.options
    // canvas绘制时的初始y偏移
    const { offsetY } = this.options
    for (let x = 0; x < timeNums.length; x++) {
      timeNums[x].offsetX = offsetX
      timeNums[x].offsetY = offsetY
      offsetX = this.drawSingleNumber(timeNums[x])
      // 两个数字连一块，应该间隔一些距离
      if (x < timeNums.length - 1) {
        offsetX += this.options.NUMBER_GAP
      }
    }

    // 第一次绘制
    if (this.currentNums.length === 0) {
      this.currentNums = timeNums
    } else {
      // 后续绘制时 替换不同的部分 并添加爆炸小球
      for (let index = 0; index < this.currentNums.length; index++) {
        if (this.currentNums[index].num !== timeNums[index].num) {
          // 不一样时，添加彩色小球
          // this.addBalls(timeNums[index])
          this.currentNums[index].num = timeNums[index].num
        }
      }
    }

    // 渲染小球
    // this.renderBalls()
    // 更新小球
    // this.updateBalls()
  }

  /**
   * 添加小球
   * @param item 小球数字
   */
  addBalls(item: ITimeCanvasNum) {
    const { num, offsetX } = item
    const numMatrix = this.options.digit[num]

    for (let y = 0; y < numMatrix.length; y++) {
      for (let x = 0; x < numMatrix[y].length; x++) {
        if (numMatrix[y][x] === 1) {
          const ball: ITimeCanvasBall = {
            offsetX: offsetX + this.options.RADIUS + this.options.RADIUS * 2 * x,
            offsetY: this.options.offsetY + this.options.RADIUS + this.options.RADIUS * 2 * y,
            color: this.options.colors[Math.floor(Math.random() * this.options.colors.length)],
            g: 1.5 + Math.random(),
            vx: Math.pow(-1, Math.ceil(Math.random() * 10)) * 4 + Math.random(),
            vy: -5
          }
          this.balls.push(ball)
        }
      }
    }
  }

  /**
   * 渲染小球
   */
  renderBalls() {
    for (let index = 0; index < this.balls.length; index++) {
      const ball = this.balls[index]
      this.context.beginPath()
      this.context.fillStyle = this.balls[index].color
      this.context.arc(ball.offsetX, ball.offsetY, this.options.RADIUS, 0, 2 * Math.PI)
      this.context.fill()
    }
  }

  /**
   * 更新小球
   */
  updateBalls() {
    let i = 0
    const radius = this.options.RADIUS
    for (let index = 0; index < this.balls.length; index++) {
      const ball = this.balls[index]
      ball.offsetX += ball.vx
      ball.offsetY += ball.vy
      ball.vy += ball.g

      if (ball.offsetY > (this.height - radius)) {
        ball.offsetY = this.height - radius
        ball.vy = -ball.vy * this.options.u
      }

      if (ball.offsetX > radius && ball.offsetX < (this.width - radius)) {
        this.balls[i] = this.balls[index]
        i++
      }
    }

    // 去除出边界的球
    for (;i < this.balls.length; i++) {
      this.balls.pop()
    }

    // 防止切换至其他窗口 仍然在生成粒子
    if (this.balls.length > 100) {
      this.balls = []
    }
  }

  /**
   * 获取单个数字
   * @param timeNums 数字
   */
  drawSingleNumber(timeNums: ITimeCanvasNum): number {
    const numMatrix = this.options.digit[timeNums.num]
    const radius = this.options.RADIUS

    for (let y = 0; y < numMatrix.length; y++) {
      for (let x = 0; x < numMatrix[y].length; x++) {
        if (numMatrix[y][x] === 1) {
          this.context.beginPath()
          const arcX = timeNums.offsetX + radius + radius * 2 * x
          const arcY = timeNums.offsetY + radius + radius * 2 * y
          this.context.arc(arcX, arcY, radius, 0, 2 * Math.PI)
          this.context.fill()
          this.context.fillStyle = this.options.timeColor
        }
      }
    }
    this.context.beginPath()
    timeNums.offsetX += numMatrix[0].length * radius * 2

    return timeNums.offsetX as number
  }
}
